<template>
  <div id="canvasid" class="main">
    <div style="float: left">
    <canvas
      style="background:white;"
      :id="radom"
      :width="width"
      :height="height"
      :style="{'cursor':cursor,  'width':`${width}px`,'height':`${height}px` , 'border-radius': '10px',
      'box-shadow': '0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)'
      }"
      @mousedown="canvasDown($event,0)"
      @mouseup="canvasUp($event,0)"
      @mousemove="canvasMove($event,0)"

      @touchstart="canvasDown($event,1)"
      @touchend="canvasUp($event,1)"
      @touchmove="canvasMove($event,1)"
    >
    </canvas>

      <el-row :style="{'height':`${buttonHeight}px`}">
        <el-button @click="changeType('curve')" type="primary" icon="el-icon-edit" circle></el-button>
        <el-button  @click="changeType('circle')" type="success" icon="el-icon-chat-round" circle></el-button>
        <el-button @click="changeType('rec')" type="info" icon="el-icon-chat-square" circle></el-button>
        <el-button  @click="undo(userid,true)" type="danger" icon="el-icon-back" circle></el-button>
        <el-button  @click="clearUs(userid,true)" type="danger" icon="el-icon-delete" circle></el-button>
        <el-button  @click="clearAll(userid,true)" type="danger" icon="el-icon-delete-solid" circle></el-button>
      </el-row>
    </div>

      <div style=" overflow:hidden;background: coral" :style="{'height':`${height}px` }">

        <div id="dialogue_box"   style=" overflow-y: auto; height: 300px; margin-bottom: 10px;">

          <div v-for="(item, index) in Infocount" :key="index" class="bubbleTail" >
              {{item}}
          </div>

        </div>
        <div style="overflow:hidden; height: 120px;">
          <el-input v-model="groupid" placeholder="group"></el-input>
          <el-input v-model="userid" placeholder="user"></el-input>

          <el-button
            :type="isopen?'success':'danger'"
            @click="initWebSocket">连接</el-button>
        </div>

        <!--发送消息窗-->
        <div>

          <div   @keydown.enter="sendUserMsg" style="margin-top: 1px;">
            <el-input placeholder="请输入内容"   v-model="msg">
              <el-button  @click="sendUserMsg" slot="append">发送</el-button>
            </el-input>
          </div>

        </div>


      </div>




      <div class="lower" :style="{'top':`${height+buttonHeight}px`}" >
            <vue-baberrage class="barrages-drop"
              :isShow= "barrageIsShow"
              :barrageList = "barrageList"
              :loop = "barrageLoop"
            >
            </vue-baberrage>
      </div>




  </div>
</template>

<script>
 const uuid = require('node-uuid')
 import { MESSAGE_TYPE } from 'vue-baberrage'
 import logo from '@/assets/logo.png'

export default {
  name: 'HelloWorld',
  mounted(){
    //初始化画板
    this.initDraw()

    //图片拖动上传
    let _this = this;
    var dropbox = document.getElementById('canvasid');
    dropbox.addEventListener("drop",this.uploadImg,false)
    dropbox.addEventListener("dragleave",function (e) {
      e.stopPropagation();
      e.preventDefault();
      _this.borderhover =  false;
    })
    dropbox.addEventListener("dragenter",function (e) {
      e.stopPropagation();
      e.preventDefault();
      _this.borderhover =  true;
    })
    dropbox.addEventListener("dragover",function (e) {
      e.stopPropagation();
      e.preventDefault();
      _this.borderhover =  true
    })

    //监听键盘

    document.onkeydown = function(e) {//事件对象兼容
      let e1 = e || event || window.event || arguments.callee.caller.arguments[0]
      if(e1.keyCode==32){//空格
        _this.moveImg(true)
      }
    }

    document.onkeyup = function(e) {//事件对象兼容
      let e1 = e || event || window.event || arguments.callee.caller.arguments[0]
      _this.moveImg(false)

    }

  },
  methods:{
    //初始化画布
    initDraw(){
      const canvas = document.getElementById(this.radom)
      this.context = canvas.getContext('2d')
      this.context.clearRect(0, 0, this.width, this.height);
      // 初始化画笔
      this.context.lineWidth = this.lineWidth
      this.context.strokeStyle = this.lineColor

    },
    // 鼠标按下
    canvasDown (e,type) {
      if(!this.isopen){return}
      this.canvasMoveUse = true
      //获取当前坐标
      let canvasX=0;
      let canvasY=0;
      if(type==0){//pc获取坐标
        canvasX = e.clientX
        canvasY = e.clientY
      }else{//移动端获取坐标
        canvasX = e.touches[0].clientX
        canvasY = e.touches[0].clientY
      }
      // 记录起始点和起始状态
      this.beginRec[this.userid] = {x:canvasX, y:canvasY}
      if (this.canDraw && this.cursor=='crosshair') {//如果可以绘制，并且光标是十字（未按空格）

        if(this.lineType != 'curve'){//如果不是铅笔
        //获取当前图
        this.lastImage = this.context.getImageData(0, 0, this.width, this.height)
        }
        this.drawLocalhost(this.userid,this.lineType,1,canvasX,canvasY,canvasX,canvasY,true);
      }else{//如是按下空格
        this.canDraw=false//改成不能绘制，并标记拖动
      }
    },
    //鼠标抬起
    canvasUp(e,type){
      if(!this.isopen){return}
        this.canvasMoveUse = false
      //获取当前坐标
      let canvasX=0;
      let canvasY=0;
      if(type==0){
        canvasX = e.clientX
        canvasY = e.clientY
      }else{
        canvasX = e.touches[0].clientX
        canvasY = e.touches[0].clientY
      }

      if (this.canDraw && this.cursor=='crosshair' ) { //如果可以绘制，并且光标是十字
        this.drawLocalhost(this.userid,this.lineType,3,canvasX,canvasY,this.beginRec[this.userid].x,this.beginRec[this.userid].y,true);
      }

      if(!this.canDraw){

        this.canDraw=true
        //拿到上一次的坐标
        const lastx =this.imgxy.x
        const lasty =this.imgxy.y
        //保存本次坐标
        this.imgxy.x=canvasX-this.beginRec[this.userid].x+lastx
        this.imgxy.y=canvasY-this.beginRec[this.userid].y+lasty
          //重绘
       this.refreshImg(false,false)
        //发送坐标消息
        let changeImg = {
          type:6,
          data:{
            x:this.imgxy.x,
            y:this.imgxy.y
          }};
        this.websocketsend(JSON.stringify(changeImg));

      }


    },
    //鼠标移动
    canvasMove (e,type) {
      if(!this.isopen){return}
      //获取当前坐标
      let canvasX=0;
      let canvasY=0;
      if(type==0){
        canvasX = e.clientX
        canvasY = e.clientY
      }else{
        canvasX = e.touches[0].clientX
        canvasY = e.touches[0].clientY
      }
      //如果是绘图
      if (this.cursor=='crosshair' && this.canDraw && this.canvasMoveUse) {
        this.drawLocalhost(this.userid,this.lineType,2,canvasX,canvasY,this.beginRec[this.userid].x,this.beginRec[this.userid].y,true)
      }

      //如果按下空格，表示拖背景图
      if(this.cursor=='pointer' && this.canDraw==false && this.canvasMoveUse){
            this.moveImgXY(canvasX-this.beginRec[this.userid].x,canvasY-this.beginRec[this.userid].y
            ,this.imgxy.x,this.imgxy.y
            )
      }

    },

    //绘制 isSend:如果是重新绘制,就不推流和不存历史记录
    drawLocalhost(user,type,action,x,y,beginx,beginy,isSend){
      //移动
      if(action==2){

        if (type === 'curve') {//曲线
          this.points[this.userid].push({x:x,y:y})

          if(this.points[this.userid].length>3){
            const lastTwoPoints = this.points[this.userid].slice(-2);
            const controlPoint = lastTwoPoints[0];
            const endPoint = {
              x: (lastTwoPoints[0].x + lastTwoPoints[1].x) / 2,
              y: (lastTwoPoints[0].y + lastTwoPoints[1].y) / 2,
            }
            this.context.beginPath()
            // this.context.globalAlpha=0.5;
            //本地曲线初始位置
            this.context.moveTo( this.beginPoint[this.userid].x,  this.beginPoint[this.userid].y);
            this.context.quadraticCurveTo(controlPoint.x, controlPoint.y, endPoint.x, endPoint.y);
            //初始位置等于结束位置
            this.beginPoint[this.userid] = endPoint;
            this.context.stroke()
          }

        }
       else if (type === 'rec') { // 绘制矩形时恢复起始点状态再重新绘制

          this.context.putImageData(this.lastImage, 0, 0)//根据初始图绘制,不然会出现多个图
          this.context.beginPath()
          this.context.rect(beginx, beginy, x - beginx, y - beginy)
          this.context.stroke()
        } else if (type === 'circle') {// 绘制椭圆时恢复起始点状态再重新绘制
          this.context.putImageData(this.lastImage, 0, 0)//根据初始图绘制,不然会出现多个图
          this.context.beginPath();
          const rx = (beginx-x)/2;
          const ry = (beginy-y)/2;
          const r = Math.sqrt(rx*rx+ry*ry);
          this.context.arc(rx+x,ry+y,r,0,Math.PI*2); // 第5个参数默认是false-顺时针
          this.context.stroke()
        }

      }

      //按下
      else if(action==1){
        //一条曲线数组
        this.points[this.userid] =[{x:beginx,y:beginy}]
        //存储曲线当前xy,作为下一次绘制曲线参考起点
        this.beginPoint[this.userid] ={x:beginx,y:beginy}
      }

      //抬起
       else if(action==3){
        this.points[this.userid]=[]//清空铅笔
        if(!isSend && type != 'curve'){ //拉流矩形或椭圆直接在当前画板上加上
          if(type === 'rec'){//矩形
            this.context.beginPath()
            this.context.rect(beginx, beginy, x - beginx, y - beginy)
            this.context.stroke()
          }else if (type === 'circle'){//圆
            this.context.beginPath()
            const rx = (beginx-x)/2;
            const ry = (beginy-y)/2;
            const r = Math.sqrt(rx*rx+ry*ry);
            this.context.arc(rx+x,ry+y,r,0,Math.PI*2); // 第5个参数默认是false-顺时针
            this.context.stroke();
          }

        }

      }
       //撤销（其他人撤销）
      else if (action==0){
        this.undo(user,isSend)
      }
      if(isSend){

          //铅笔每次都发
          if(type === 'curve'){
            //存储本次绘制信息,用于撤销
            this.drawInfo.push({
              x: x,
              y: y,
              beginx:beginx,
              beginy:beginy,
              type: type,
              action:action,
              userid:this.userid

            })
            //发送到服务器
            this.sendCanVas(this.userid,type,action,x,y,beginx,beginy)

          }else if (action==3){//其他只保存最后一个

            //存储本次绘制信息,用于撤销
            this.drawInfo.push({
              x: x,
              y: y,
              beginx:beginx,
              beginy:beginy,
              type: type,
              action:action,
              userid:this.userid
            })
            //发送到服务器
            this.sendCanVas(this.userid,type,action,x,y,beginx,beginy)
          }
      }

    },

    //改变图片位置
    moveImgXY(x,y,thisx,thisy){
      this.context.clearRect(0, 0, this.width, this.height);
      this.context.beginPath()
      this.context.drawImage(this.img, x+thisx, y+thisy);
      this.context.stroke();
    },
    //改变画笔
    changeType(type){
        this.lineType=type
    },
    //撤销
    undo(unuserid,isSend){
      if(this.drawInfo.length>0){
        let undotype

        for(let i=this.drawInfo.length-1; i>=0; i--){

          if(this.drawInfo[i].userid==unuserid){
            if(
              !(
              (this.drawInfo[i].type=='curve' && this.drawInfo[i].action==1) ||//铅笔剪到按下
              (this.drawInfo[i].type!='curve' &&this.drawInfo[i].action==3)//剩下的剪到抬起
              )
            ){
              this.drawInfo.splice(i,1);
            }else{
              undotype=this.drawInfo[i].type
              this.drawInfo.splice(i,1);//拿到撤销的type
            break;}

          }
        }
            //清空
         this.refreshImg(false,false)//更新背景
        //如果是自己并且不会重绘缓存 就发送撤销步骤
        if(isSend&&unuserid==this.userid){
          this.sendCanVas(this.userid,undotype,0,0,0,0,0)
        }

      }
    },

  //清空自己的画板
    clearUs (userid,isSend) {
      if(!this.isopen){return}
      for(let i=this.drawInfo.length-1; i>=0; i--){
        if(this.drawInfo[i].userid == userid){
          this.drawInfo.splice(i,1);
        }
      }
      this.refreshImg(false,false)

      if(isSend){
        //发送清空自己
        const clearUsData = {
          type:7,
          data:{ }};
        this.websocketsend(JSON.stringify(clearUsData));
      }


    },
    //清空全部的画板
    clearAll (userid,isSend) {
      if(!this.isopen){return}
      this.drawInfo=[]
      this.refreshImg(false,false)

      if(isSend){
        //发送清空所有
        const clearAllData = {
          type:8,
          data:{ }};
        this.websocketsend(JSON.stringify(clearAllData));
      }


    },

    //消息框加载
    load(msg){
      this.Infocount.push( this.dateFormat(new Date()) +'  '+ msg)
      //永远在最底部
      let div = document.getElementById('dialogue_box');
      div.scrollTop = div.scrollHeight;

    },

    initWebSocket(){ //初始化weosocket
      if(this.websock!=null){
        this.websock.close()
      }
      if(this.userid!='' && this.groupid!=''){
        const wsuri = this.$baseURL.replace("https","wss").replace("http","ws");;
        this.websock = new WebSocket(wsuri+'/go/'+this.groupid+"/"+this.userid);
        this.websock.onmessage = this.websocketonmessage;
        this.websock.onopen = this.websocketonopen;
        this.websock.onerror = this.websocketonerror;
        this.websock.onclose = this.websocketclose;
      }

    },
    websocketonopen(){ //连接建立之后执行send方法登录
      this.isopen=true
      this.addToList('登录成功')
      //登录成功，拉取画板
      let getCanvas = {
        type:4,
        data:{}};
      this.websocketsend(JSON.stringify(getCanvas));
      //请求拉取背景url
      let getImg = {
        type:9,
        data:{}};
      this.websocketsend(JSON.stringify(getImg));

    },
    websocketonerror(){//连接建立失败重连
      console.log("建立连接失败")
     // this.initWebSocket();
      this.isopen=false
    },
    websocketonmessage(e){ //数据接收
      let parse = JSON.parse(e.data)

      //用户发送消息
        if(parse.type==2){
        this.load(parse.data.userid+' : '+parse.data.msg)//打印日志
        this.addToList(parse.data.userid+'说:'+parse.data.msg)
      }

      //用户上线通知
      else  if(parse.type==3){
        this.addToList(parse.data.userid+'来了，当前组人数:'+parse.data.activeCount)
      }

      //用户掉线通知
      else  if(parse.type==4){
        this.addToList(parse.data.userid+'走了，当前组人数:'+parse.data.activeCount)
      }
      //拉取画板消息
    else  if(parse.type==5){

        if(parse.data.action==3 && (parse.data.type=='rec' || parse.data.type=='circle')  ){
          this.addToList(parse.data.userid+'画了一个'
            +(  parse.data.type=='rec'?"方块" : parse.data.type=='circle'?"圆":'' )
          )
        }

          this.drawPullCanvas(parse.data)
      }
      //刷新背景图
      else  if(parse.type==6){
        //如果不是自己切换才更新
        if(this.userid!=parse.data.userid){
          this.url=parse.data.url
          this.refreshImg(true,false)
        }
      }
      //移动背景图
      else if(parse.type==7){
        this.imgxy.x=parse.data.x
        this.imgxy.y=parse.data.y
        //重绘
        this.refreshImg(false,false)
      }
      //某人清空画板
      else if (parse.type==8){
        this.addToList(parse.data.userid+'清空了自己的画板')
            this.clearUs(parse.data.userid,false)
      }
      //清空所有画板
      else if(parse.type==9){
        this.addToList(parse.data.userid+'清空了整个画板')
        this.clearAll(parse.data.userid,false)
      }
      //拉取刷新背景
      else if(parse.type==10){
        this.url=parse.data.imgurl
        this.imgxy.x=parse.data.x
        this.imgxy.y=parse.data.y
        this.refreshImg(true,false)
      }

    },
    websocketsend(Data){//数据发送
      this.websock.send(Data);
    },
    websocketclose(e){  //关闭
      console.log('断开连接',e);
      this.isopen=false
    },
//时间格式化函数，此处仅针对yyyy-MM-dd hh:mm:ss 的格式进行格式化
    dateFormat(time) {
      var date=new Date(time);
      var year=date.getFullYear();
      /* 在日期格式中，月份是从0开始的，因此要加0
       * 使用三元表达式在小于10的前面加0，以达到格式统一  如 09:11:05
       * */
      var month= date.getMonth()+1<10 ? "0"+(date.getMonth()+1) : date.getMonth()+1;
      var day=date.getDate()<10 ? "0"+date.getDate() : date.getDate();
      var hours=date.getHours()<10 ? "0"+date.getHours() : date.getHours();
      var minutes=date.getMinutes()<10 ? "0"+date.getMinutes() : date.getMinutes();
      var seconds=date.getSeconds()<10 ? "0"+date.getSeconds() : date.getSeconds();
      // 拼接
      return year+"-"+month+"-"+day+" "+hours+":"+minutes+":"+seconds;
    },
  //发送画板内容
    sendCanVas(u,type,action,x,y,beginx,beginy){

      let data = {
        type:3,
        data:{
          userid:u,
          type:type,
          action:action,
          x:x,
          y:y,
          beginx:beginx,
          beginy:beginy
        }};
      this.websocketsend(JSON.stringify(data));
    },

    //画拉取的画板
    drawPullCanvas (parse) {
        this.drawInfo.push(parse)
      //清空
      this.refreshImg(false,false);

    },
    //改变画笔颜色
    changeColor(){
      this.lineColor='orange'
    },
    //刷新背景图 isloadImg:是否需要刷新背景图
    refreshImg(isloadImg,issend){

      if(isloadImg){//如果需要刷新背景图
        this.img.setAttribute('crossOrigin', 'Anonymous')
        this.img.src = this.url
        this.img.onload = () => {
          this.context.clearRect(0, 0, this.width, this.height);
          this.context.beginPath()
          this.context.drawImage(this.img, this.imgxy.x, this.imgxy.y);
          this.context.stroke();
          this.imgOnLoad=true//标记图片加载完成
          //重新画
          for(let a of this.drawInfo ){
            this.drawLocalhost(a.userid, a.type,a.action,a.x,a.y , a.beginx,a.beginy,false)
          }
            //是否需要发送切换动作
          if(issend){
            //发送切换图消息
            let changeImg = {
              type:5,
              data:{
                url:this.url
              }};
            this.websocketsend(JSON.stringify(changeImg));

          }

        }

          }
      else{
        this.context.clearRect(0, 0, this.width, this.height);
        //有图片直接覆盖

        if(this.imgOnLoad){

          this.context.beginPath()
          this.context.drawImage(this.img, this.imgxy.x, this.imgxy.y);
          this.context.stroke();
        }
        //重新画
        for(let a of this.drawInfo ){
          this.drawLocalhost(a.userid, a.type,a.action,a.x,a.y , a.beginx,a.beginy,false)
        }

      }

    },
    //文件拖拽
    uploadImg(e){
      //阻止拖图片默认事件
      this.borderhover = false
      e.stopPropagation();
      e.preventDefault();
      let fileData = e.dataTransfer.files;
      this.uploadFile(fileData)

    },
    uploadFile(file){   //渲染上传文件
      //一次只能上传一张
      if(file.length==1){
        if(file[0].type.indexOf('image') === 0){  //如果是图片
          //图片的大小
          if (file[0].size > 1024 * 1000) {
            alert('请选择10M以内的图片！');
            return false;
          }

          let form = new FormData();
          form.append('file', file[0], file[0].name);
          //接口部分
          this.$http.post("/upload/img", form, {
            headers: {
              'Content-Type': 'multipart/form-data'
            }
          }).then(response => {
            this.url=response.data.url
            this.refreshImg(true,true)//更新背景
          }).catch(function(err) {
            console.log(err);
          });


        }else {
          alert("不支持此类型文件")
        }
      }

    },

    moveImg(isen){//拖动背景 isen:是否按下
      if(isen){
        this.cursor='pointer'//按下改变光标为拖动
      }else{//松开键盘
        this.cursor='crosshair'//标记为十字
      }
    },
//添加弹幕
    addToList (msg) {
      this.barrageList.push({
        id: ++this.currentId,
        avatar: logo,
        msg: msg,
        barrageStyle:'red',
        time: 5,
        type: MESSAGE_TYPE.NORMAL,
      })
    },
    //发送消息
    sendUserMsg(){
      if(!this.isopen){return}
      if(this.msg!=''){
        let sendUserMsgData = {
          type:2,
          data:{msg:this.msg}
        };
        this.websocketsend(JSON.stringify(sendUserMsgData));
        this.msg='';
      }

    }

  },
  data () {
    return {
      websock: null,//websocket
      isopen:false,//是否已经建立连接
      groupid:1,//当前组
      userid:'',//用户
      radom: uuid.v4(),  // 同一页面多次渲染时，用于区分元素的id
      width:960,
      height:540,
      //
      // width:640,
      // height:480,
      buttonHeight:40,
      context: {},     // canvas对象
      cursor:'crosshair',//光标，默认十字架
      img: new Image(),  // 背景图片缓存
      imgxy:{x:0,y:0}, //记录当前图片的位置

      imgOnLoad:false, //图片是否加载完成
      url:'', //默认背景图片地址
      lineWidth:2,//绘画笔宽度
      lineColor:"red",//绘画笔颜色
      canDraw:true,//绘画开关
      canvasMoveUse: false,      // 是否处于绘制状态
      beginRec: [],//用于绘制圆和矩形，保存初始坐标
      lastImage:null,//当前图，用于绘制矩形和园
      drawInfo: [],// 储存历史消息
      lineType:"curve",//画笔类型,默认曲线
      points:[],//当前曲线数组
      beginPoint:{},//存储曲线上一次的坐标（绘制一条曲线时使用）
      Infocount:[],//消息框
      fileData:[],//上传的文件
      msg: '',//用户发的消息

      barrageIsShow: true,
      currentId : 0,
      barrageLoop: false,
      barrageList: []


    }
  }
}
</script>

<style scoped>
  .main{
    height: 100%;
    margin: 0px;
    padding: 0px;
  }

  .lower{
    width: 100%;
    position: absolute;
    bottom: 0px;
    left: 0px;
  }

  . baberrage-lane {
    border-radius: 100px;
    background: #e68fba;
    color: #fff;
  }

  /*气泡框*/
  .bubbleTail {
    word-break:break-all;
    width:450px;
    height:auto;
    background:#F8C301;
    border-radius:5px; /* 圆角 */
    margin-bottom: 20px;

  }


</style>
